package com.youi.service.impl;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.youi.common.Common;
import com.youi.common.DelStatus;
import com.youi.entity.Goods;
import com.youi.entity.Goodssize;
import com.youi.entity.Ordergoods;
import com.youi.entity.Userorder;
import com.youi.service.GoodsService;
import com.youi.service.GoodssizeService;
import com.youi.service.MerchantService;
import com.youi.service.OrdergoodsService;
import com.youi.service.UserorderService;
@Service
public class TransactionalUserorderService {

	 private static HashMap<String, Object> params(String key, Object value) {
	        HashMap<String, Object> result = new HashMap<>();
	        result.put(key, value);
	        return result;
	    }

	    private static HashMap<String, Object> paramsNODel(String key, Object value) {
	        HashMap<String, Object> result = paramsNODel();
	        result.put(key, value);
	        return result;
	    }

	    private static HashMap<String, Object> paramsNODel() {
	        HashMap<String, Object> result = new HashMap<>();
	        result.put(Common.DELSTATUS, DelStatus.NODEL);
	        return result;
	    }

	    static private Comparator<Long> longComparator = new Comparator<Long>() {
	        @Override
	        public int compare(Long o1, Long o2) {
	            return Long.compare(o1,o2);
	        }
	    };

	    @Autowired
	    private UserorderService userorderService;
	    @Autowired
	    private MerchantService merchantService;
	    @Autowired
	    private GoodsService goodsService;
	    @Autowired
	    private OrdergoodsService ordergoodsService;
	    @Autowired
	    private GoodssizeService goodssizeService;
	
	  /**
     * 取消/退款订单的事务过程
     * @param userorder 要取消的userorder
     * @param setRefund 是否取消订单的时候还要设置退款标志
     */
    @Transactional
    public void cancelOrdergoods(Userorder userorder,boolean setRefund){
        //先锁userorder
        userorder = userorderService.getForUpdate(userorder.getId());
        //已经被取消/退款了，不做任何操作返回（也不提示出错）
        if (userorder.getStatus()==-1){
            return;
        }
        //获取订单明细
        List<Ordergoods> ordergoodsList=ordergoodsService.getByParams(
                paramsNODel("orderId", userorder.getId()));

        //不清楚要不要做订单明细为空的判断
//        if (ordergoodsList.isEmpty()) {
//            throw new BusinessException(CommonInfoUtil.DATAERROR, "订单没有明细");
//        }

        //采集所有的goodsId和goodssizeId
        HashSet<Long> allGoodsIdSet = new HashSet<>();
        HashSet<Long> allGoodssizeIdSet = new HashSet<>();
        //并且记录每一条ordergoodsId（订单明细）对应的goodssize的Id（货品规格ID）
        HashMap<Long,Long> ordergoodsId_to_goodssizeId = new HashMap<>();
        for (Ordergoods ordergoods : ordergoodsList) {
            HashMap<String, Object> prams = new HashMap<>();
            prams.put(Common.DELSTATUS, DelStatus.NODEL);
            prams.put("goodsId", ordergoods.getGoodsId());
            prams.put("specification", ordergoods.getSpecification());
            prams.put("price", ordergoods.getSlaePrice());
            Goodssize goodssize = goodssizeService.getByParam(prams);
            if (goodssize != null) {
                Goods goods = goodsService.get(goodssize.getGoodsId());
//                    goodsService.getGoodsMsg(goods, user);
                ordergoodsId_to_goodssizeId.put(ordergoods.getId(),goodssize.getId());
                if (goods != null) {
                    allGoodsIdSet.add(goods.getId());
                    allGoodssizeIdSet.add(goodssize.getId());
                }
            } //如果取不到规格就跳过，不清楚要不要做出错
        }
        //排序，锁定和加载
        LockedGoodsAndGoodssize lockedData =
                new LockedGoodsAndGoodssize(allGoodsIdSet,allGoodssizeIdSet);

        //锁定完成后逐个更新数量
        for (Ordergoods ordergoods : ordergoodsList) {
            Long goodssizeId = ordergoodsId_to_goodssizeId.get(ordergoods.getId());
            Goodssize goodssize=lockedData.goodssizeMap.get( goodssizeId ) ;
            if (goodssize!=null) {
                Goods goods=lockedData.goodsMap.get(goodssize.getGoodsId());
//                    goodsService.getGoodsMsg(goods, user);
                if (goods!=null) {
                    //在锁定的数据里做变更
                    //管理的数据：goodssize.realStockNum,goodssize.saleNum,goods.realSaleCnt
                    if (goodssize.getRealStockNum()!=null) {
                        goodssize.setRealStockNum(goodssize.getRealStockNum()+ordergoods.getCount());
                    }
                    if (goodssize.getSaleNum()!=null) {
                        goodssize.setSaleNum(goodssize.getSaleNum()-ordergoods.getCount());
                    }
                    goods.setRealSaleCnt(goods.getRealSaleCnt()-ordergoods.getCount());
                    //保存锁定的数据
                    goodssizeService.saveOrUpdate(goodssize);
                    goodsService.saveOrUpdate(goods);
                }
            }
        }

        //最后修改订单状态
        userorder.setStatus(-1);
        if (setRefund) {
            userorder.setRefund(1);
        }
        userorder.setGmtClose(new Date());
        userorderService.saveOrUpdate(userorder);
    }
    
    //加锁帮助类，可以对提供的货品和型号ID集合进行排序和加锁，并保留加锁后加载的对象
    private class LockedGoodsAndGoodssize{

        HashMap<Long,Goods> goodsMap = new HashMap<>();
        HashMap<Long,Goodssize> goodssizeMap = new HashMap<>();

        LockedGoodsAndGoodssize(HashSet<Long> allGoodsIdSet,HashSet<Long> allGoodssizeIdSet){
            ArrayList<Long> allGoodsIds = new ArrayList<>(allGoodsIdSet);
            ArrayList<Long> allGoodssizeIds = new ArrayList<>(allGoodssizeIdSet);
            allGoodsIds.sort(longComparator);
            allGoodssizeIds.sort(longComparator);
            //排序完成后的数据进行加锁获取记录,顺序为先goods，然后是goodssize
            for(Long goodsId : allGoodsIds){
                Goods goods = goodsService.getForUpdate(goodsId);
                goodsMap.put(goods.getId(),goods);
            }
            for(Long _goodssizeId : allGoodssizeIds){
                Goodssize goodssize=goodssizeService.getForUpdate(_goodssizeId);
                goodssizeMap.put(goodssize.getId(),goodssize);
            }
        }
    }
}
